// src/main/java/Util/SimpleConnectionPool.java
package com.hp.Util;                                                        // 包名：Util

import javax.sql.DataSource;                                         // 标准数据源接口
import java.io.PrintWriter;                                          // DataSource 规定的日志输出（可不实现）
import java.lang.reflect.Proxy;                                      // 动态代理，用来拦截 Connection.close()
import java.sql.*;                                                   // JDBC 基本类型
import java.time.Duration;                                           // 用于 isValid() 的超时配置
import java.util.Properties;                                         // JDBC 连接属性（用户名/密码）
import java.util.concurrent.ArrayBlockingQueue;                      // 有界阻塞队列
import java.util.concurrent.BlockingQueue;                           // 阻塞队列接口

/**
 * SimpleConnectionPool：教学/作业用的极简数据库连接池
 * 特点：
 *  - 构造时预建固定数量的连接，放入阻塞队列
 *  - 通过动态代理把 Connection.close() 改造成“归还到池”，而不是真关闭
 *  - getConnection() 取不到会阻塞，取到后做 isValid() 检查，失效则重建
 * 生产建议用 HikariCP 等成熟连接池；这个类更便于看懂和跟进作业要求
 */
public class SimpleConnectionPool implements DataSource {            // 实现 DataSource，供 JDBC 使用
    private final String jdbcUrl;                                    // JDBC URL（含库名和参数）
    private final Properties props;                                   // 连接参数（user/password 等）
    private final BlockingQueue<Connection> pool;                     // 连接池（阻塞队列）

    public SimpleConnectionPool(String jdbcUrl, String username, String password, int poolSize) throws SQLException {
        this.jdbcUrl = jdbcUrl;                                      // 保存 JDBC URL
        this.props = new Properties();                               // 创建 Properties
        props.setProperty("user", username);                          // 设置用户名
        props.setProperty("password", password);                      // 设置密码
        this.pool = new ArrayBlockingQueue<>(poolSize);              // 固定大小的池
        for (int i = 0; i < poolSize; i++) pool.add(newPooledConnection()); // 预创建连接并放入池
    }

    // 创建一个“可回收”的连接（通过动态代理把 close() 变成归还到池）
    private Connection newPooledConnection() throws SQLException {
        final Connection real = DriverManager.getConnection(jdbcUrl, props); // 打开真实物理连接
        return (Connection) Proxy.newProxyInstance(                  // 创建代理连接
                real.getClass().getClassLoader(),                    // 使用真实连接的类加载器
                new Class[]{Connection.class},                       // 代理实现 Connection 接口
                (proxy, method, args) -> {                           // 调用处理器
                    if ("close".equals(method.getName())) {          // 调用 close() 时
                        pool.offer((Connection) proxy);               // 把代理连接放回池
                        return null;                                  // 不执行真正关闭
                    }
                    return method.invoke(real, args);                 // 其他方法转发给真实连接
                }
        );
    }

    @Override
    public Connection getConnection() throws SQLException {          // 从池里取连接
        try {
            Connection c = pool.take();                              // 阻塞等待一个连接
            // 做一次轻量可用性检查（避免死连接）
            if (!c.isValid((int) Duration.ofSeconds(3).toSeconds())) // 3 秒超时
                c = newPooledConnection();                           // 失效就重建一个新的代理连接
            return c;                                                // 返回可用连接
        } catch (InterruptedException e) {                           // 线程被中断
            Thread.currentThread().interrupt();                      // 恢复中断标志
            throw new SQLException("Interrupted while waiting for a DB connection", e); // 包装异常
        }
    }

    // 下面这些是 DataSource 接口要求，但这里用不到，简单实现/占位即可
    @Override public Connection getConnection(String username, String password) { throw new UnsupportedOperationException(); }
    @Override public <T> T unwrap(Class<T> iface) { throw new UnsupportedOperationException(); }
    @Override public boolean isWrapperFor(Class<?> iface) { return false; }
    @Override public PrintWriter getLogWriter() { return null; }
    @Override public void setLogWriter(PrintWriter out) { }
    @Override public void setLoginTimeout(int seconds) { DriverManager.setLoginTimeout(seconds); }
    @Override public int getLoginTimeout() { return DriverManager.getLoginTimeout(); }
    @Override public java.util.logging.Logger getParentLogger() { return java.util.logging.Logger.getGlobal(); }

    // 应用关闭时（如 Servlet destroy 或 main 结束），可调用以便快速释放池中代理（示例级别）
    public void shutdown() { pool.clear(); }
}
